home *** CD-ROM | disk | FTP | other *** search
- /* sparc/audio.c
- vi:ts=3 sw=3:
- */
-
- /* $Id: audio.c,v 4.15 1995/05/12 20:40:46 espie Exp espie $
- * $Log: audio.c,v $
- * Revision 4.15 1995/05/12 20:40:46 espie
- * Added frequency change.
- *
- * Revision 4.14 1995/05/12 13:52:39 espie
- * New synchronization.
- *
- * Revision 4.13 1995/03/03 14:22:55 espie
- * Fixed audio info bug.
- *
- * Revision 4.12 1995/02/26 23:07:14 espie
- * solaris.
- *
- * Revision 4.11 1995/02/25 15:44:15 espie
- * discard_buffer incorrect.
- *
- * Revision 4.10 1995/02/24 15:36:39 espie
- * Finally fixed speed/sync/late start.
- *
- * Revision 4.9 1995/02/24 13:48:39 espie
- * Fixed minor bug (interaction between pause and -sync).
- *
- * Revision 4.8 1995/02/24 13:43:52 espie
- * Added -sync feature.
- * In the absence of -sync, pause half a second at start to allow for
- * data to accumulate in buffer first.
- * Suppressed update freq on the fly since audioctl does not allow it.
- *
- * Revision 4.7 1995/02/23 22:41:45 espie
- * Added # of bits.
- *
- * Revision 4.6 1995/02/23 16:42:27 espie
- * Began conversion to `common' model.
- *
- * Revision 4.5 1995/02/23 13:52:30 espie
- * primary, secondary -> primary+secondary, primary-secondary
- * strike out 2 multiplications out of 4 !
- *
- * Revision 4.4 1995/02/21 17:57:55 espie
- * Internal problem: RCS not working.
- *
- * Revision 4.3 1995/02/01 16:43:47 espie
- * 23 bit samples.
- *
- * Revision 4.2 1994/01/13 09:19:08 espie
- * Forgotten something.
- *
- * Revision 4.0 1994/01/11 18:16:36 espie
- * New release.
- *
- * Revision 3.14 1993/12/04 16:12:50 espie
- * BOOL -> boolean.
- * Merged ss10/solaris.
- * Merged support for solaris together.
- * Fixed /16 bug.
- * Corrected mix problem.
- * restore stty.
- * Sync pseudo call.
- * Added update_frequency call, mostly unchecked
- * Added finetune.
- * Protracker commands.
- *
- * Revision 1.3 1992/11/17 15:38:00 espie
- * discard_buffer() call for snappier interface calls.
- * - Unified support for all sparcs.
- * - moved down to level 2 io.
- */
-
- #include "defs.h"
- #include "extern.h"
- #ifdef SOLARIS
- #include <sys/audioio.h>
- #else
- #include <sun/audioio.h>
- #endif
- #include <sys/ioctl.h>
- #include <fcntl.h>
- #include <stropts.h>
- #include <signal.h>
-
- #define DEFAULT_SET_MIX
- #define DEFAULT_BUFFERS
- #define NEW_OUTPUT_SAMPLES_AWARE
- #define NEW_FUNCS
-
- #include "Arch/common.c"
-
- /* things that aren't defined in all sun/audioio.h */
-
- #ifndef AUDIO_ENCODING_LINEAR
- #define AUDIO_ENCODING_LINEAR (3)
- #endif
- #ifndef AUDIO_GETDEV
- #define AUDIO_GETDEV _IOR(A, 4, int)
- #endif
- #ifndef AUDIO_DEV_UNKNOWN
- #define AUDIO_DEV_UNKNOWN (0)
- #endif
- #ifndef AUDIO_DEV_AMD
- #define AUDIO_DEV_AMD (1)
- #endif
-
- ID("$Id: audio.c,v 4.15 1995/05/12 20:40:46 espie Exp espie $")
-
- LOCAL int audio;
- LOCAL int written;
- LOCAL int wait_samples;
- LOCAL int tsync;
-
- LOCAL int ADVANCE_TAGS= -1;
-
- LOCAL struct audio_info ainfo, ainfo2;
-
- /* set_synchronize(): pause the audio device at start of play,
- * in order to accumulate enough samples before playing
- */
- LOCAL void set_synchronize()
- {
- written = ainfo.play.eof;
- if (!ainfo2.play.pause)
- {
- ainfo2.play.pause = TRUE;
- ioctl(audio, AUDIO_SETINFO, &ainfo2);
- /* number of samples to accumulate */
- wait_samples = ainfo.play.sample_rate / 2;
- }
- else
- wait_samples = 0;
- }
-
- LOCAL int possible[] = { 8000, 9600, 11025, 16000, 18900, 22050, 32000,
- 37800, 44100, 48000, 0};
-
- int open_audio(f, s)
- int f;
- int s;
- {
- int type;
-
- int basic;
- #ifdef SOLARIS
- audio_device_t dev;
-
- audio = open("/dev/audio", O_WRONLY);
- #else
- audio = open("/dev/audio", O_WRONLY|O_NDELAY);
- #endif
-
-
- basic = 0;
- if (audio == -1)
- end_all("Error: could not open audio");
-
- /* round frequency to acceptable value */
- f = best_frequency(f, possible, 22050);
-
- /* check whether we know about AUDIO_ENCODING_LINEAR */
- AUDIO_INITINFO(&ainfo);
- AUDIO_INITINFO(&ainfo2);
- #ifdef SOLARIS
- ioctl(audio, AUDIO_GETDEV, &dev);
- if (strcmp(dev.name, "SUNW,dbri") != 0)
- #else
- if (ioctl(audio, AUDIO_GETDEV, &type) ||
- type == AUDIO_DEV_UNKNOWN || type == AUDIO_DEV_AMD || basic)
- #endif
- {
- /* not a new ss5/10/20 -> revert to base quality audio */
- stereo = 0;
- dsize = 1;
- f = 8000;
- ainfo.play.encoding = AUDIO_ENCODING_ULAW;
- ainfo.play.channels = 1;
- }
- else
- {
- /* tentative set up */
- stereo = s;
- ainfo.play.precision = 16;
- dsize = 2;
- if (stereo)
- ainfo.play.channels = 2;
- else
- ainfo.play.channels = 1;
- /* try it */
- ainfo.play.encoding = AUDIO_ENCODING_LINEAR;
- }
- ainfo.play.sample_rate = f;
- if (ioctl(audio, AUDIO_SETINFO, &ainfo) != 0)
- /* didn't work: fatal problem */
- end_all("Error: AUDIO_SETINFO");
- idx = 0;
- samples_max = ainfo.play.channels*ainfo.play.sample_rate;
- buffer = (char *)malloc(dsize*samples_max);
- buffer16 = (short *)buffer;
- if (!buffer)
- end_all("Error: could not allocate buffer");
-
- set_synchronize();
- return f;
- }
-
- void set_synchro(s)
- int s;
- {
- tsync = s;
- }
-
- LOCAL int newfreq;
-
- int update_frequency()
- {
- if (newfreq)
- {
- newfreq = 0;
- samples_max = ainfo.play.channels * ainfo.play.sample_rate;
- buffer = realloc(buffer, dsize * samples_max);
- buffer16 = (short *)buffer;
- return ainfo.play.sample_rate;
- }
- else
- return 0;
-
- /* the current implementation of the audio device does not allow
- * output frequency change through /dev/audioctl
- * -> this code is not needed
- int oldfreq;
-
- oldfreq = ainfo.play.sample_rate;
- if (ioctl(audio, AUDIO_GETINFO, &ainfo) == 0)
- {
- if (oldfreq != ainfo.play.sample_rate)
- {
- samples_max = ainfo.play.channels * ainfo.play.sample_rate;
- buffer = realloc(buffer, dsize * samples_max);
- buffer16 = (short *)buffer;
- return ainfo.play.sample_rate;
- }
- }
- return 0;
- */
- }
-
- void audio_ui(c)
- int c;
- {
- int i;
-
- switch(c)
- {
- case '+':
- if (audio & ainfo.play.encoding == AUDIO_ENCODING_LINEAR)
- {
- for (i = 0; ; i++)
- if (possible[i] == ainfo.play.sample_rate)
- break;
- if (possible[i+1])
- {
- ainfo.play.sample_rate = possible[i+1];
- if (ioctl(audio, AUDIO_SETINFO, &ainfo) == 0)
- newfreq = 1;
- }
- }
- break;
- case '-':
- if (audio & ainfo.play.encoding == AUDIO_ENCODING_LINEAR)
- {
- for (i = 0; ; i++)
- if (possible[i] == ainfo.play.sample_rate)
- break;
- if (i)
- {
- ainfo.play.sample_rate = possible[i-1];
- if (ioctl(audio, AUDIO_SETINFO, &ainfo) == 0)
- newfreq = 1;
- }
- }
- break;
- default:
- }
- }
-
-
- void output_samples(left, right, n)
- int left, right, n;
- {
-
- switch(ainfo.play.encoding)
- {
- case AUDIO_ENCODING_LINEAR:
- add_samples16(left, right, n);
- break;
- case AUDIO_ENCODING_ULAW:
- buffer[idx++] = linear2ulaw((left + right) >> (n-14));
- break;
- default:
- end_all("Error:Unknown audio encoding");
- }
- }
-
-
- /* synchronize stuff with audio output */
-
- struct tagged
- {
- struct tagged *next; /* simply linked list */
- void (*f) P((GENERIC *)); /* function to call */
- GENERIC p; /* and parameter */
- int when; /* number of chunks to let go before calling */
- }
- *start, /* what still to output */
- *end; /* where to add new tags */
-
-
-
- /* flush_tags: use tags that have gone by recently */
- LOCAL void flush_tags()
- {
- ioctl(audio, AUDIO_GETINFO, &ainfo);
- if (start)
- {
- while (start && start->when <= ainfo.play.eof + ADVANCE_TAGS)
- {
- struct tagged *tofree;
-
- (*start->f)(start->p);
- tofree = start;
- start = start->next;
- free(tofree);
- }
- }
- }
-
- /* remove unused tags at end */
- LOCAL void remove_pending_tags()
- {
- while (start)
- {
- struct tagged *tofree;
-
- tofree = start;
- start = start->next;
- free(tofree);
- }
- }
-
- void sync_audio(function, parameter)
- void (*function) P((void *));
- GENERIC parameter;
- {
- struct tagged *t;
-
- t = malloc(sizeof(struct tagged));
- if (!t)
- {
- (*function)(parameter);
- return;
- }
- /* build new tag */
- t->next = 0;
- t->f = function;
- t->p = parameter;
- t->when = written;
-
- /* add it to list */
- if (start)
- end->next = t;
- else
- start = t;
- end = t;
-
- /* set up for next tag */
- write(audio, buffer, 0);
- written++;
-
- if (!tsync)
- flush_tags();
- }
-
- void flush_buffer()
- {
- int actual;
- int number;
-
- actual = write(audio, buffer, dsize * idx);
- if (actual == -1)
- notice("Write to audio failed");
- else if (actual != dsize * idx)
- notice("Short write to audio");
- if (wait_samples)
- { /* currently paused ? */
- wait_samples -= actual;
- if (wait_samples <= 0)
- { /* right number of samples gone by ? */
- wait_samples = 0;
- ainfo2.play.pause = FALSE;
- ioctl(audio, AUDIO_SETINFO, &ainfo2);
- }
- }
- if (tsync)
- flush_tags();
- idx = 0;
- }
-
- void discard_buffer()
- {
- remove_pending_tags();
- ioctl(audio, I_FLUSH, FLUSHW);
- if (wait_samples)
- {
- ainfo2.play.pause = FALSE;
- ioctl(audio, AUDIO_SETINFO, &ainfo2);
- wait_samples = 0;
- }
- set_synchronize();
- }
-
- void close_audio()
- {
- remove_pending_tags();
- free(buffer);
- close(audio);
- }
-
- int output_resolution()
- {
- return 16;
- }
-